#include "config.h"
#include <string.h>

#include "xIPC.h"
#include "aux_types.h"
#include "aux_errno.h"
#include "aux_debugmsg.h"
#include "aux_queuemanager.h"
#include "aux_idmanager.h"
/*
 * the manager of the nodes,
 * each node has a member pData,
 * it point to an object of TQueue
 */
static TQueue s_tQueue_Manager = {0};

/*
 * static function
 * compare the ids of two queues,
 * return
 *      ERRNO_TRUE: two queue's id are different
 *      ERRNO_FALSE: same
 *      <0: error
 */
static EErrNo s_xIPCQueueChkTQueueIdDiff(TQueue **ptQue1,
                                                u32     nSize,
                                                TQueue *ptQue2)
{
#define __FUNCTION_NAME__ "s_xIPCQueueChkTQueueIdDiff"
    if (!ptQue1 || !ptQue2)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    /* id only set when init, so not need lock */
    return (((*ptQue1)->nId) != (ptQue2->nId)) ? ERRNO_TRUE : ERRNO_FALSE;
#undef __FUNCTION_NAME__
}

static EErrNo s_xIPCQueueChkTQueueIdSame(TQueue **ptQue1,
                                                u32     nSize,
                                                TQueue *ptQue2)
{
#define __FUNCTION_NAME__ "s_xIPCQueueChkTQueueIdSame"
    if (!ptQue1 || !ptQue2)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    /* id only set when init, so not need lock */
    return (((*ptQue1)->nId) == (ptQue2->nId)) ? ERRNO_TRUE : ERRNO_FALSE;
#undef __FUNCTION_NAME__
}


/*
 * return error or fail, or success
 */
static EErrNo s_xIPCQueuePopHead_without_lock(TQueue *ptQue,
                                                          void  **ppData,
                                                          u32    *pnSize)
{
#define __FUNCTION_NAME__ "s_xIPCQueuePopHead_without_lock"

    TQueueNode * pQueNode = NULL;
    u32          nTraCnt  = 0;

    if (!ptQue || !ppData)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (0 == ptQue->nNodeCnt)
    {
        AUX_DEBUG_STR("queue empty\n");
        return ERRNO_NOTFIND;
    }

    // node count >= 1
    pQueNode = ptQue->ptHeadNode;
    if (pQueNode)
    {
        ptQue->ptHeadNode = pQueNode->ptNextNode;
        *ppData = pQueNode->pData;

        if (pnSize)
            *pnSize = pQueNode->nSize;

        free(pQueNode);
    }

    (ptQue->nNodeCnt)--;
    if (0 == ptQue->nNodeCnt)
    {
        ptQue->ptHeadNode = NULL;
        ptQue->ptTailNode = NULL;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

/*
 * add a node in the tail of queue with no lock protect
 * it will malloc, and NOT USE the parameter pointer
 */
static EErrNo s_xIPCQueuePushBack_without_lock(TQueue *ptQue,
                                                            void  *pData,
                                                            u32    nSize)
{
#define __FUNCTION_NAME__ "s_xIPCQueuePushBack_without_lock"

    u8         *pabyBuffer = NULL;
    TQueueNode *ptQueNode  = NULL;

    if (!ptQue || !pData || !nSize)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    pabyBuffer = (u8 *)malloc(nSize);
    if (!pabyBuffer)
    {
        AUX_ERR_STR("malloc fail\n");
        return -ERRNO_EMALLOC_FAIL;
    }

    ptQueNode = (TQueueNode *)malloc(sizeof(TQueueNode));
    if (!ptQueNode)
    {
        free(pabyBuffer);
        AUX_ERR_STR("malloc fail\n");
        return -ERRNO_EMALLOC_FAIL;
    }

    memcpy(pabyBuffer, pData, nSize);
    ptQueNode->nSize = nSize;
    ptQueNode->pData = (void *)pabyBuffer;
    ptQueNode->ptNextNode = NULL;

    if (NULL == ptQue->ptHeadNode)
        ptQue->ptHeadNode = ptQueNode;

    if (NULL == ptQue->ptTailNode)
        ptQue->ptTailNode = ptQueNode;

    ptQue->ptTailNode->ptNextNode = ptQueNode;
    ptQue->ptTailNode             = ptQueNode;
    ptQue->ptTailNode->ptNextNode = NULL;
    (ptQue->nNodeCnt)++;

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

static EErrNo s_xIPCQueueClear_without_lock(TQueue *ptQue,
                                                    pfQueueDataDeconstructor pCb)
{
#define __FUNCTION_NAME__ "s_xIPCQueueClear_without_lock"

    void  *pData;
    u32    nSize;

    if (!ptQue)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    while (ERRNO_SUCCESS == s_xIPCQueuePopHead_without_lock(
                                                        ptQue, &pData, &nSize))
    {
        if (pData)
        {
            if (!pCb)
            {
                if (ptQue->pfDestroy)
                    (ptQue->pfDestroy)(pData, nSize);
                else
                    free(pData);
            }
            else
            {
                pCb(pData, nSize);
            }
        }

        if (0 == ptQue->nNodeCnt)
            break;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

static EErrNo s_xIPCQueueDeinit_internal(TQueue *ptQue,
                                                pfQueueDataDeconstructor pCb,
                                                u8 byDelFromManager)
{
#define __FUNCTION_NAME__ "s_xIPCQueueDeinit_internal"

    EErrNo eRet;
    pthread_mutex_t tLock;

    if (!ptQue)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        memset(ptQue, 0, sizeof(TQueue));
        return ERRNO_SUCCESS;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (byDelFromManager)
    {
        eRet = xIPCQueueDeleteFirstIfCbReturnTrue(&s_tQueue_Manager,
                                 (pfQueueDataHandler)s_xIPCQueueChkTQueueIdSame,
                                               (void *)ptQue);
        if ((eRet != ERRNO_SUCCESS && eRet != ERRNO_NOTFIND))
        {
            /* delete fail */
            AUX_ERR_STR("delete from manager fail\n");
            pthread_mutex_unlock(&(ptQue->tQueueMutexLock));
            return ERRNO_FAIL;
        }
        else
        {
            aux_prt_debug("delete from manager success, id %d name %s\n",
                        ptQue->nId, ptQue->szName);
        }
    }
    eRet = s_xIPCQueueClear_without_lock(ptQue, pCb);
    tLock = ptQue->tQueueMutexLock;
    memset(ptQue, 0, sizeof(TQueue));
    //pthread_mutex_unlock(&tLock);
    pthread_mutex_destroy(&tLock);
    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

static EErrNo s_xIPCQueueDeleteOneNodeOfManager(void *pData, u32 nSize)
{
    TQueue *ptQueue;
    /*
     * if the queue manager find queue that not released,
     * just free the node, and the memory that the member pointer point
     * This may cause memory leakage.So take care.
     */
    if (!pData)
        return -ERRNO_EPARAMETER_INVALID;

    ptQueue = *((TQueue **)pData);
    aux_prt_err("WARNING!!!s_xIPCQueueDeleteOneNodeOfManager "
                "find queue manager have un-released queue %p,id %d, name %s\n",
                ptQueue, ptQueue->nId, ptQueue->szName);
    /*
     * because release the node called in the deinit the manager, the node has
     * been released, so the parameter byDelFromManager of the following function
     * is set to 0.
     */
    return s_xIPCQueueDeinit_internal(ptQueue, NULL, 0);
}

/*
 * static function
 * init one queues, add it to the manager if needed
 * return
 *      ERRNO_SUCCESS: init ok
 *      ERRNO_FAIL: init fail
 *      <0: error
 */
static EErrNo s_xIPCQueueInit_internal(TQueue *ptQue,
                                              const char   *pszName,
                                              u8      byAdd2Manager,
                                              pfQueueDataDeconstructor pDestroy)
{
#define __FUNCTION_NAME__ "s_xIPCQueueInit_internal"

    if (!ptQue)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    memset(ptQue, 0, sizeof(TQueue));
    ptQue->nNodeCnt   = 0;
    ptQue->ptHeadNode = NULL;
    ptQue->ptTailNode = NULL;
    ptQue->pfDestroy = pDestroy;

    if (pszName)
    {
        if (strlen(pszName) >= QUEUE_NAME_LENGTH_MAX)
            return -ERRNO_EPARAMETER_INVALID;
        else
            strcpy(&(ptQue->szName[0]), pszName);
    } /*
    else
        already memset, all '\0'
    */

    if (ERRNO_SUCCESS != xIPCIdManagerGetId(&(ptQue->nId)))
        return ERRNO_FAIL;

    if (pthread_mutex_init(&(ptQue->tQueueMutexLock), NULL))
    {
        AUX_ERR_STR("init mutex fail\n");
        return -ERRNO_EINIT_LOCK_FAIL;
    }

    /* just store the queue pointer to the queue */
    if (byAdd2Manager)
    {
        if (ERRNO_SUCCESS != xIPCQueueCheckAllTrueThenPushBack(
                                 &s_tQueue_Manager,
                                 (pfQueueDataHandler)s_xIPCQueueChkTQueueIdDiff,
                                 (void *)ptQue,
                                 (void *)(&ptQue),
                                 sizeof(TQueue *)))
        {

            pthread_mutex_destroy(&(ptQue->tQueueMutexLock));
            AUX_ERR_STR("xIPCQueueCheckAllTrueThenPushBack fail\n");
            return ERRNO_FAIL;
        }
    }
    else
    {
        aux_prt_debug("add queue success %p\n", ptQue);
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}



EErrNo xIPCQueueInit(TQueue *ptQue, const char *pszName,
                           pfQueueDataDeconstructor pDestroy)
{
    return s_xIPCQueueInit_internal(ptQue, pszName, 0, pDestroy);
}

EErrNo xIPCQueueChkValid(const TQueue * ptQue)
{
    return (((NULL == ptQue) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))) ?
         ERRNO_INVALID : ERRNO_VALID);
}

/*
 * traverse all the nodes,
 * and use pCb to compare the data of each node with
 * the pParameter ,if same, just delete this node
 */
EErrNo xIPCQueueDeleteFirstIfCbReturnTrue(TQueue *ptQue,
                                                       pfQueueDataHandler pCb,
                                                       void *pParameter)
{
#define __FUNCTION_NAME__ "xIPCQueueDeleteFirstIfCbReturnTrue"

    TQueueNode * pQueNode     = NULL;
    TQueueNode * pQuePrevNode = NULL;
    u32          nHaveTraCnt  = 0;
    u8           byFound      = 0;

    if (!ptQue || !pCb)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (0 == ptQue->nNodeCnt)
        goto EXIT_WITH_LOCK;

    for (nHaveTraCnt = 0, pQueNode = ptQue->ptHeadNode, pQuePrevNode = NULL;
         pQueNode && (nHaveTraCnt < ptQue->nNodeCnt);
         pQuePrevNode = pQueNode, pQueNode = pQueNode->ptNextNode, nHaveTraCnt++)
    {
        if (ERRNO_TRUE == pCb(pQueNode->pData, pQueNode->nSize, pParameter))
        {
            byFound = 1;
            break;
        }
    }

    if (byFound) /* find */
    {
        if (NULL == pQuePrevNode) /* the first node */
        {
            void *pData = NULL;
            u32   nSize;

            if (ERRNO_SUCCESS ==
                s_xIPCQueuePopHead_without_lock(ptQue, &pData, &nSize))
            {
                if (pData)
                    free(pData);
                goto EXIT_WITH_LOCK;
            }
        }
        else /* node cnt >= 2 */
        {
            pQuePrevNode->ptNextNode = pQueNode->ptNextNode;

            if (pQueNode->pData)
            {
                free(pQueNode->pData);
                pQueNode->pData =  NULL;
            }

            free(pQueNode);
            pQueNode = NULL;
            (ptQue->nNodeCnt)--; /* because left node exist, so not fix */
        }
    }

EXIT_WITH_LOCK:
    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    if (byFound)
        return ERRNO_SUCCESS;
    else
        return ERRNO_NOTFIND;
#undef __FUNCTION_NAME__
}

/* WARNING:may cause free and referrence conflict. */
EErrNo xIPCQueueGetFirstIfCbReturnTrue(TQueue *ptQue,
                                                   pfQueueDataHandler pCb,
                                                   void  *pParameter,
                                                   void **ppData,
                                                   u32   *pnSize)
{
#define __FUNCTION_NAME__ "xIPCQueueDeleteFirstIfCbReturnTrue"

    TQueueNode * pQueNode     = NULL;
    TQueueNode * pQuePrevNode = NULL;
    u32          nHaveTraCnt  = 0;
    u8           byFound      = 0;
    EErrNo       eRet         = ERRNO_SUCCESS;

    if (!ptQue || !pCb || (!ppData && !pnSize))
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    /* empty, so fail */
    if (0 == ptQue->nNodeCnt)
    {
        AUX_DEBUG_STR("queue has been empty\n");
        eRet = ERRNO_FAIL;
        goto EXIT_WITH_LOCK;
    }

    for (nHaveTraCnt = 0, pQueNode = ptQue->ptHeadNode, pQuePrevNode = NULL;
         pQueNode && nHaveTraCnt < ptQue->nNodeCnt;
         pQuePrevNode = pQueNode, pQueNode = pQueNode->ptNextNode, nHaveTraCnt++)
    {
        if (ERRNO_TRUE == pCb(pQueNode->pData, pQueNode->nSize, pParameter))
        {
            byFound = 1;
            break;
        }
    }

    if (byFound) /* find */
    {
        if (ppData)
            *ppData = pQueNode->pData;

        if (pnSize)
            *pnSize = pQueNode->nSize;
    }
    else
    {
        eRet = ERRNO_FAIL;
    }

EXIT_WITH_LOCK:
    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return eRet;
#undef __FUNCTION_NAME__
}


EErrNo xIPCQueuePushBack(TQueue *ptQue, void *pData, u32 nSize)
{
#define __FUNCTION_NAME__ "xIPCQueuePushBack"

    u8         *pabyBuffer = NULL;
    TQueueNode *ptQueNode  = NULL;

    if (!ptQue || !pData || !nSize)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    pabyBuffer = (u8 *)malloc(nSize);
    if (!pabyBuffer)
    {
        AUX_ERR_STR("malloc buffer to store data fail\n");
        return -ERRNO_EMALLOC_FAIL;
    }

    ptQueNode = (TQueueNode *) malloc(sizeof(TQueueNode));
    if (!ptQueNode)
    {
        free(pabyBuffer);
        AUX_ERR_STR("malloc for node fail\n");
        return -ERRNO_EMALLOC_FAIL;
    }

    memcpy(pabyBuffer, pData, nSize);
    ptQueNode->nSize = nSize;
    ptQueNode->pData = (void *)pabyBuffer;
    ptQueNode->ptNextNode = NULL;

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        free(pabyBuffer);
        free(ptQueNode);
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (NULL == ptQue->ptHeadNode)
        ptQue->ptHeadNode = ptQueNode;

    if (NULL == ptQue->ptTailNode)
        ptQue->ptTailNode = ptQueNode;

    ptQue->ptTailNode->ptNextNode = ptQueNode;
    ptQue->ptTailNode             = ptQueNode;
    ptQue->ptTailNode->ptNextNode = NULL;
    (ptQue->nNodeCnt)++;

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPCQueuePushBackPointer(TQueue *ptQue, void *pData)
{
    return xIPCQueuePushBack(ptQue, &pData, sizeof(void *));
}

/*
 * use pCb to check each node, if fail, just return
 * if pCb is NULL, just push back
 */
EErrNo xIPCQueueCheckAllTrueThenPushBack(TQueue *ptQue,
                                                      pfQueueDataHandler pCb,
                                                      void *pParameter,
                                                      void *pData,
                                                      u32   nSize)
{
#define __FUNCTION_NAME__ "xIPCQueueCheckAllTrueThenPushBack"

    TQueueNode * pQueNode = NULL;
    u32          nTraCnt  = 0;
    EErrNo       eRet     = ERRNO_TRUE;

    /*
     * the callback function is NULL and the pData is NULL,
     * THIS NOT ALLOWED
     */
    if (!ptQue || (!pCb && !pData))
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("get lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (0 == ptQue->nNodeCnt || !pCb) /* node cnt is 0, or no callback */
        goto PUSHBACK;

    for (nTraCnt = 0, pQueNode = ptQue->ptHeadNode;
         pQueNode && (nTraCnt < ptQue->nNodeCnt);
         pQueNode = pQueNode->ptNextNode, ++nTraCnt)
    {
        eRet = pCb(pQueNode->pData, pQueNode->nSize, pParameter);

        if (ERRNO_FALSE == eRet)
            goto UNLOCK_EXIT;
    }

PUSHBACK:
    if ((ERRNO_TRUE == eRet) && pData && (nSize > 0))
    {
        eRet = s_xIPCQueuePushBack_without_lock(ptQue, pData, nSize);
    }

UNLOCK_EXIT:
    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return eRet;
#undef __FUNCTION_NAME__
}


EErrNo xIPCQueueTraverse(TQueue *ptQue, pfQueueDataHandler pCb,
                                void *pParameter)
{
#define __FUNCTION_NAME__ "xIPCQueueTraverse"

    TQueueNode * pQueNode = NULL;
    u32          nTraCnt  = 0;

    if (!ptQue || !pCb)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }


    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (0 == ptQue->nNodeCnt)
        goto EXIT_WITH_LOCK;

    for (nTraCnt = 0, pQueNode = ptQue->ptHeadNode;
         pQueNode && nTraCnt < ptQue->nNodeCnt;
         pQueNode = pQueNode->ptNextNode, nTraCnt++)
        pCb(pQueNode->pData, pQueNode->nSize, pParameter);

EXIT_WITH_LOCK:
    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPCQueueTraverseUntilCbReturnFalse(TQueue *ptQue,
                                                        pfQueueDataHandler pCb,
                                                        void *pParameter)
{
#define __FUNCTION_NAME__ "xIPCQueueTraverseUntilCbReturnFalse"

    TQueueNode * pQueNode = NULL;
    u32          nTraCnt  = 0;

    if (!ptQue || !pCb)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }


    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (0 == ptQue->nNodeCnt)
        goto EXIT_WITH_LOCK;

    for (nTraCnt = 0, pQueNode = ptQue->ptHeadNode;
         pQueNode && nTraCnt < ptQue->nNodeCnt;
         pQueNode = pQueNode->ptNextNode, nTraCnt++)
    {
        if (ERRNO_FALSE == pCb(pQueNode->pData, pQueNode->nSize, pParameter))
            break;
    }

EXIT_WITH_LOCK:
    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}


EErrNo xIPCQueueNodeCnt(TQueue *ptQue, u32 *pnCnt)
{
#define __FUNCTION_NAME__ "xIPCQueueNodeCnt"

    if (!ptQue || !pnCnt)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_DEBUG_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }


    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    *pnCnt = ptQue->nNodeCnt;

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");

        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPCQueuePopHead(TQueue *ptQue, void **ppData, u32 *pnSize)
{
#define __FUNCTION_NAME__ "xIPCQueueNodeCnt"

    EErrNo eRet = ERRNO_FAIL;

    if (!ptQue || !ppData)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_DEBUG_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    eRet = s_xIPCQueuePopHead_without_lock(ptQue, ppData, pnSize);

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return eRet;
#undef __FUNCTION_NAME__
}

EErrNo xIPCQueuePopHeadPointer(TQueue *ptQue, void **ppData)
{
    u32   nSize = 0;
    void *pData = NULL;

    if (ERRNO_SUCCESS == xIPCQueuePopHead(ptQue, &pData, &nSize))
    {
        *ppData = *((void **)pData);
        free(pData);
        return ERRNO_SUCCESS;
    }
    else
    {
        return ERRNO_FAIL;
    }
}


EErrNo xIPCQueueDeleteHead(TQueue *ptQue, pfQueueDataDeconstructor pCb)
{
#define __FUNCTION_NAME__ "xIPCQueueDeleteHead"

    EErrNo eRet  = ERRNO_FAIL;
    void  *pData = NULL;
    u32    nSize;

    if (!ptQue)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    eRet = s_xIPCQueuePopHead_without_lock(ptQue, &pData, &nSize);

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        // -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    if (ERRNO_SUCCESS != eRet)
        return ERRNO_FAIL;

    if (pCb)
    {
        eRet = pCb(pData, nSize);
    }
    else
    {
        if (pData)
        {
            free(pData);
        }
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

/* WARNING:may cause free and referrence conflict. */
/* get the data of the first node, the data is malloc in heap */
EErrNo xIPCQueueGetHead(TQueue *ptQue, void **ppData, u32 *pnSize)
{
#define __FUNCTION_NAME__ "xIPCQueueGetHead"

    EErrNo eRet = ERRNO_SUCCESS;

    if ((!ptQue) || (!ppData))
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (0 == ptQue->nNodeCnt)
    {
        eRet = ERRNO_FAIL;
    }
    else
    {
        *ppData = ptQue->ptHeadNode->pData;

        if (pnSize)
            *pnSize = ptQue->ptHeadNode->nSize;
        eRet = ERRNO_SUCCESS;
    }

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return eRet;
#undef __FUNCTION_NAME__
}

/* WARNING: may cause problem, for example, when use by other place, free it */
EErrNo xIPCQueueGetHeadPointer(TQueue *ptQue, void **ppData)
{
    u32   nSize = 0;
    void *pData = NULL;

    if (ERRNO_SUCCESS == xIPCQueueGetHead(ptQue, &pData, &nSize))
    {
        *ppData = *((void **)pData);
        return ERRNO_SUCCESS;
    }
    else
    {
        return ERRNO_FAIL;
    }
}

static EErrNo s_checkPointerSameWithParameter(void *pData,
                                                    u32 nSize, void *pParameter)
{
    void *pPointer = *((void **)pData);

    if (!pData || nSize < sizeof(void *) || !pParameter)
        return ERRNO_FALSE;

    if (pPointer == pParameter)
        return ERRNO_TRUE;
    else
        return ERRNO_FALSE;
}

/* ONLY delete pointer in the queue, not delete the memory the pointer point to */
EErrNo xIPCQueueDelPointer(TQueue *ptQue, void *pData)
{
    EErrNo eRet;

    do {
        eRet = xIPCQueueDeleteFirstIfCbReturnTrue(ptQue,
                               s_checkPointerSameWithParameter, pData);
    } while(ERRNO_SUCCESS == eRet);

    if (ERRNO_NOTFIND == eRet)
        return ERRNO_SUCCESS;
    else
        return ERRNO_FAIL;
}


EErrNo xIPCQueueClear(TQueue *ptQue, pfQueueDataDeconstructor pCb)
{
#define __FUNCTION_NAME__ "xIPCQueueClear"

    EErrNo eRet;

    if (!ptQue)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    eRet = s_xIPCQueueClear_without_lock(ptQue, pCb);

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return eRet;
#undef __FUNCTION_NAME__
}

/* this function will remove the queue from the manager */
EErrNo   xIPCQueueDeinit(TQueue *ptQueue, pfQueueDataDeconstructor pCb)
{
    return s_xIPCQueueDeinit_internal(ptQueue, pCb, 0);
}

EErrNo xIPCQueueLock(TQueue *ptQue)
{
#define __FUNCTION_NAME__ "xIPCQueueLock"

    if (!ptQue)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_lock(&(ptQue->tQueueMutexLock)) ||
        (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock))))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPCQueueUnlock(TQueue *ptQue)
{
#define __FUNCTION_NAME__ "xIPCQueueUnlock"

    if (!ptQue)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_INVALID == xIPCChkPthreadMutexValid(&(ptQue->tQueueMutexLock)))
    {
        AUX_ERR_STR("queue lock invalid\n");
        return -ERRNO_EINVALID_MUTEX;
    }

    if (pthread_mutex_unlock(&(ptQue->tQueueMutexLock)))
    {
        /* fail */
        AUX_DEBUG_STR_SZPONTER("queue:", ptQue->szName);
        AUX_DEBUG_STR_INT("id:",    ptQue->nId);
        AUX_DEBUG_STR("mutex unlock fail\n");
        return -ERRNO_EFATAL_MUTEX_UNLOCK;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}


EErrNo xIPCComponentQueueManagerInit()
{
    memset(&s_tQueue_Manager, 0, sizeof(TQueue));
    if (ERRNO_SUCCESS != s_xIPCQueueInit_internal(&s_tQueue_Manager,
                                        "Component_QueueManager",
                                        0, NULL))
        return ERRNO_FAIL;
    else
        return ERRNO_SUCCESS;
}

EErrNo xIPCComponentQueueManagerDeinit()
{
    if (ERRNO_SUCCESS != s_xIPCQueueDeinit_internal(&s_tQueue_Manager,
                                              s_xIPCQueueDeleteOneNodeOfManager,
                                              0))
        return ERRNO_FAIL;
    else
        return ERRNO_SUCCESS;
}



